% Rewriter
:- source.
:- use_module(library(lists)).
%:- use_module('/home/msridhar/AsRewriter/seclp/abc_parser.yap').
:- style_check(all).
:- yap_flag(unknown, error).

:-use_module('abc_parser.yap').
:-use_module('marking.yap').
:-use_module('rewrite_utilities.yap').
:-use_module('rewrite_methods_resourcebound.yap').

get_marked_instr_lists(InFile,NewMarkedList) :-
	get_AST(InFile, T),
	abc_parser:getABC(method_bodies,T,MethodBodies),
	initialize_marklist(MethodBodies,MarkedList),
	modify_AST(T, MarkedList, _NewT, NewMarkedList).

rewrite(InFile, OutFile, NewMarkedList, SecRelIndices) :-
	%abc_parser:parseFile(InFile, _, Bytes, T),
	
	get_AST(InFile, T),

	abc_parser:getABC(method_bodies,T,MethodBodies),
	initialize_marklist(MethodBodies,MarkedList),
	modify_AST(T, MarkedList, NewT, NewMarkedList),
	b_getval(instrindices,SecRelIndices),
	%	trace,
	abc_parser:abcFile(NewT, F, []),
	%spy(abc_parser:write_file),
	%trace,
	abc_parser:write_file(OutFile, F).
	

	%print_marklists(NewMarkedList).
	%print_arraycount(NewMarkedList,0,'NewMarkedList').
	%told.

spit_parse_tree(InFile, ParseTree) :-

	open('out.txt','write',Stream),
	tell(Stream),
write(Offset), write( ' - '), writeln(I),
	abc_parser:readFile(InFile,Bytes),
	writeln(Bytes),
	abc_parser:abcFile(ParseTree,Bytes,[]),
	told.
%just get the Abstract Syntax Tree for a particular file
%ABCObject does not work for the URL per object example, so going to 
%skip using that - don't know why the cut is there.
get_AST(File, ABC) :-
	abc_parser:readFile(File, Bytes),
	abc_parser:abcFile(ABC, Bytes, []),
	abc_parser:init_classes, !.
	
%-----------------------> TOP-LEVEL REWRITER
%
silly_modify_AST(T, T, []).

%Given the old Abstract Syntax Tree, Old_T, makes desired changes
%to that to get a new Abstract Syntax Tree, New_T.
modify_AST(Old_T, MarkedList, New_T, NewMarkedList) :-
	Old_T =.. [abc, MinV, MajV, CP, MC, 
			Methods, MetaC, Metas,
		       	CC, Instances, Classes, 
			SC, Scripts, BC, MB],

    
   
	change_CP(CP, CPNew),	

	open('fileinfo.txt','append',AdStream),
	tell(AdStream),
	print_arraycount(Methods, MC, 'Methods'),
	print_arraycount(Metas, MetaC, 'Metas'),	
	print_arraycount(Instances, CC, 'Instances'),	
	print_arraycount(Classes, CC, 'Classes'),
	print_arraycount(Scripts, SC, 'Scripts'),	
	print_arraycount(MB, BC, 'MB'),
	told,

	change_methodbodyinfo(MB, MarkedList, CPNew, MBNew, NewMarkedList),
	%break,
	format('Num Method Bodies = ~w~n~n', [BC]),
	largest_method_size(MB,LargestSize,0),
	format('Largest size = ~w~n~n', [LargestSize]),

	NewMC is MC,
	NewMethods = Methods,
	NewCC is CC,
	NewInstances = Instances,
	NewClasses = Classes, 

	NewBC is BC, 
	New_T =.. [abc, MinV, MajV, CPNew, NewMC, 
			NewMethods, MetaC, Metas, NewCC, 
			NewInstances, NewClasses, SC, 
			Scripts, NewBC, MBNew].

largest_method_size([M1|MBs],LargestSize,Max) :-
	M1 =.. [method_body, _Method, _MS, _LC, _ISD, _MSD, _CL, C, _EC, _E, _TC, _T],
	length(C, CLength),
	(CLength >= Max) -> 
		largest_method_size(MBs,LargestSize,CLength);
		largest_method_size(MBs,LargestSize,Max).
largest_method_size([],Max,Max).

%------------------>REWRITE CONSTANT POOL 
%changes the constant pool. Has helper functions below
%for adding integers, strings and multinames and changing
%their counts appropriately.
change_CP(Old_CP, New_CP) :-
	Old_CP =.. [cpoolinfo, IntCount, Integers, UIntCount, 
			UIntegers, DoubleCount, Doubles, StringCount,
		       	Strings, NameSpaceCount, NameSpaces, NSSetCount,
		       	NSSets, MultinameCount, Multinames],
                

	%	write(''printing before change_CP ------------------>\n'),
	open('fileinfo.txt','write',AStream),
	tell(AStream),
	print_arraycount(Integers, IntCount, 'OldI'),
	print_arraycount(UIntegers, UIntCount, 'OldUI'),
	print_arraycount(Doubles, DoubleCount, 'OldD'),
	print_arraycount(Strings, StringCount, 'OldCP_Strings'),
	print_arraycount(NameSpaces, NameSpaceCount, 'OldCP_NameSpaces'),
	print_arraycount(NSSets, NSSetCount, 'OldCP_NSSets'),
	print_arraycount(Multinames, MultinameCount, 'OldMultinames'),
	told, 


	%add_integers(IntCount, Integers, NewIntCount, NewIntegers),
	add_strings(StringCount, Strings, NewStringCount, NewStrings),
	add_namespaces(NewStrings, NameSpaces, NameSpaceCount, NewNameSpaces, NewNameSpaceCount),
	add_multinames(NewStrings, MultinameCount, Multinames, NewMultinameCount, NewMultinames),
	New_CP =.. [cpoolinfo, IntCount, Integers, UIntCount, 
			UIntegers, DoubleCount, Doubles, NewStringCount, 
			NewStrings, NewNameSpaceCount, NewNameSpaces,
		       	NSSetCount, NSSets, NewMultinameCount, NewMultinames].

		
			%write('printing after change_CP ------------------>\n'),
			%print_arraycount(NewStrings, NewStringCount, 'NewCP_Strings'),
			%print_arraycount(NewNameSpaces, NewNameSpaceCount, 'NewCP_NameSpaces'),
			%print_arraycount(NSSets, NSSetCount, 'NewCP_NSSets'),
			%print_arraycount(NewMultinames, NewMultinameCount, 'NewMultinames'),
			%write('<-----------------------------------\n').


add_integers(IntCount, Integers, NewIntCount, NewIntegers) :-
	NewIntCount is IntCount + 1,
	%write(Integers),
	append(Integers, [1], NewIntegers).
	%write(NewIntegers).


%TODO: When adding strings, need to make sure that datatypes such as "Number",
%"void" etc. are already there, or we need to add them. For other identifiers,
%such as user-given variable names, need to make sure that they are NOT
%already there in the string array - not doing that right now.
add_strings(StringCount, Strings, NewStringCount, NewStrings) :-
	%print_arraycount(Strings, StringCount, 'String'),
	atom_codes('isOkay', L1),
	length(L1, Length1),
	S1 = string_info(Length1, L1, 'isOkay'),
	atom_codes('Number', L2),
	length(L2, Length2),
	S2 = string_info(Length2, L2, 'Number'),
	atom_codes('NativeApplication', L3),
	length(L3, Length3),
	S3 = string_info(Length3, L3, 'NativeApplication'),
	atom_codes('nativeApplication', L4),
	length(L4, Length4),
	S4 = string_info(Length4, L4, 'nativeApplication'),
	atom_codes('exit', L5),
	length(L5, Length5),
	S5 = string_info(Length5, L5, 'exit'),
	atom_codes('flash.desktop', L6),
	length(L6, Length6),
	S6 = string_info(Length6, L6, 'flash.desktop'),
	atom_codes('urlObject', L7),
	length(L7, Length7),
	S7 = string_info(Length7, L7, 'urlObject'),
	atom_codes('url', L8),
	length(L8, Length8),
	S8 = string_info(Length8, L8, 'url'),
	atom_codes('checkURL', L9),
	length(L9, Length9),
	S9 = string_info(Length9, L9, 'checkURL'),
	atom_codes('adobeURL', L10),
	length(L10, Length10),
	S10 = string_info(Length10, L10, 'adobeURL'),
	atom_codes('utdURL', L11),
	length(L11, Length11),
	S11 = string_info(Length11, L11, 'utdURL'),
	atom_codes('myURL', L12),
	length(L12, Length12),
	S12 = string_info(Length12, L12, 'myURL'),
	atom_codes('value', L13),
	length(L13, Length13),
	S13 = string_info(Length13, L13, 'value'),
	atom_codes('newURL', L14),
	length(L14, Length14),
	S14 = string_info(Length14, L14, 'newURL'),
	atom_codes('String', L15),
	length(L15, Length15),
	S15 = string_info(Length15, L15, 'String'),

	NewStringCount is StringCount + 15,
	%NewStringCount is StringCount + 2,

	append(Strings, [S1, S2, S3, S4, S5, S6, S7, S8, S9, S10, S11, S12, S13, S14, S15], NewStrings).
	%append(Strings, [S1, S2, S3, S4, S5, S6], NewStrings).
	%append(Strings, [S1, S2], NewStrings).

	%print_arraycount(NewStrings, NewStringCount, 'String').


add_namespaces(Strings, NameSpaces, NameSpaceCount, NewNameSpaces, NewNameSpaceCount) :-

	find_index_stringCP('flash.desktop', Strings, I1), 
	N1 = namespace_info('CONSTANT_PackageNamespace', I1),

	find_index_stringCP('urlObject', Strings, I2),

	%format('index for urlObject is =====================~w~n',[I2]),
	N2 = namespace_info('CONSTANT_ProtectedNamespace', I2),

	append(NameSpaces, [N1, N2], NewNameSpaces),
	NewNameSpaceCount is NameSpaceCount + 2.

%TODO: Right now hardcoding the index into the Namespace set. 
add_multinames(Strings, MultinameCount, Multinames, NewMultinameCount, NewMultinames) :-
	%print_arraycount(Multinames, MultinameCount, 'Multiname'),
	NewMultinameCount is MultinameCount + 15,
	
	find_index_stringCP('isOkay', Strings, I1),
	M1 = m_info('CONSTANT_QName', qname(1, I1)), %isOkay
	
	find_index_stringCP('Number', Strings, I2),
	M2 = m_info('CONSTANT_QName', qname(1, I2)), %Number

	find_index_stringCP('NativeApplication', Strings, I3),
	M3 = m_info('CONSTANT_QName', qname(7, I3)), %NativeApplication

	find_index_stringCP('nativeApplication', Strings, I4),
	M4 = m_info('CONSTANT_QName', qname(1, I4)), %nativeApplication

	find_index_stringCP('exit', Strings, I5),
	M5 = m_info('CONSTANT_QName', qname(1, I5)), %exit

	find_index_stringCP('flash.desktop', Strings, I6),
	M6 = m_info('CONSTANT_QName', qname(1, I6)), %flash.desktop

	find_index_stringCP('urlObject', Strings, I7),
	M7 = m_info('CONSTANT_QName', qname(1, I7)), %urlObject

	find_index_stringCP('url', Strings, I8),
	M8 = m_info('CONSTANT_QName', qname(1, I8)), %url

	find_index_stringCP('checkURL', Strings, I9),
	M9 = m_info('CONSTANT_QName', qname(1, I9)), %checkURL

	find_index_stringCP('adobeURL', Strings, I10),
	M10 = m_info('CONSTANT_QName', qname(1, I10)), %adobeURL

	find_index_stringCP('utdURL', Strings, I11),
	M11 = m_info('CONSTANT_QName', qname(1, I11)), %utdURL

	find_index_stringCP('myURL', Strings, I12),
	M12 = m_info('CONSTANT_QName', qname(1, I12)), %myURL

	find_index_stringCP('value', Strings, I13),
	M13 = m_info('CONSTANT_QName', qname(1, I13)), %value

	find_index_stringCP('newURL', Strings, I14),
	M14 = m_info('CONSTANT_QName', qname(1, I14)), %newURL

	find_index_stringCP('String', Strings, I15),
	M15 = m_info('CONSTANT_QName', qname(1, I15)), %String



	append(Multinames, [M1, M2, M3, M4, M5, M6, M7, M8, M9, M10, M11, M12, M13, M14, M15], NewMultinames).

%---------------->REWRITE METHOD INFO

change_methodcount(MC, NewMC) :-
	NewMC is MC + 1.

change_methodinfo(Methods, CP, NewMethods) :-
	M1 = method_info(0,0,[],1,[],option_info(none),param_info(none)),
%	M2 = method_info(0,0,[],0,[],option_info(none),param_info(none)),

	find_index_multinameCP('Number', CP, Type1Index),
	find_index_multinameCP('String', CP, Type2Index),
	
	CP =.. CPList,
	nth(9, CPList, Strings),
	find_index_stringCP('urlObject', Strings, NameIndex),
	M2 = method_info(2,0,[Type1Index, Type2Index],NameIndex,
			['HAS_PARAM_NAMES'],option_info(none),[0,0]),
	append(Methods, [M1, M2], NewMethods).

%---------------->REWRITE CLASSES, INSTANCES, TRAITS


%changes the class info array. Classes is an array of class_info structures.
%Each class_info structure is a tuple - Cinit - index into the method array
%of the abcFile; it references the method that is invoked when the class is 
%first created. TC - trait_count is the number of entries in the trait array,
%which holds the traits for the class. Traits is the trait array.
%
%TODO: Right now assuming that we are not adding traits to the existing class;
%instead, we are going to add another class.
%
change_classcount(OldCount, NewCount) :-
	NewCount is OldCount + 1.

change_instanceinfo(Instances, CP, NewInstances) :-

	find_index_multinameCP('urlObject', CP, NameIndex),
	find_index_multinameCP('Object', CP, SuperNameIndex),
	Flags = ['CONSTANT_ClassProtectedNs','CONSTANT_ClassSealed'],

	%find_index_namespaceCP('UnsafeURLPerObject', CP, ProtectedNSIndex),
	find_index_namespaceCP('urlObject',CP,ProtectedNSIndex),

	format('in change_instanceinfo,PNSI = ~w~n',[ProtectedNSIndex]), 
	Intrf_count is 0,
	Interface = [],


	Iinit is 181, %TODO: make generic
	TraitCount is 2,

	find_index_multinameCP('isOkay', CP, I1),
	find_index_multinameCP('url', CP, I2),

	find_index_multinameCP('Number', CP, T1),
	find_index_multinameCP('String', CP, T2),

	Traits = [trait(I1,'Trait_Slot',[],trait_slot(0,T1,0,nil),0,[]),
		  trait(I2,'Trait_Slot',[],trait_slot(0,T2,0,nil),0,[])],


%	Traits = [],

	I = instance(NameIndex, SuperNameIndex, Flags,
			  ProtectedNSIndex, Intrf_count, Interface, Iinit, 
			  TraitCount, Traits),

	append(Instances, [I], NewInstances).


change_classinfo(Classes, NewClasses) :- 
	C = class_info(180, 0, []), %TODO: make generic
	append(Classes, [C], NewClasses).

%The trait structure has five fields :- Name, Kind, Flags, Data, MC,
%Metadatas. Name is an index into the multiname array of the constant
%pool. Kind field is the kind and attributes.






